package org.kugua.strategy.impl;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.util.*;
import java.util.List;

import org.kugua.context.CaptchaContext;
import org.kugua.enums.CaptchaEnum;
import org.kugua.enums.FontEnum;
import org.kugua.dto.Captcha;
import org.kugua.strategy.ParentCaptchaStrategy;
import org.kugua.utils.RandomUtils;

import static org.kugua.utils.RandomUtils.random;

/**
 * 文本类验证码
 *
 * @author 苦瓜
 * @create 2024-08-26
 * @since 1.0.0
 */
public class TextCaptchaStrategy extends ParentCaptchaStrategy {

    /**
     * 默认生成的字符串
     */
    private static final int len = 4;

    /**
     * 旋转效果
     */
    private boolean isRotate = true;

    /**
     * 默认的字符集
     */
    public static final char[] ALPHA = {
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
            'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S',
            'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a',
            'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j',
            'k', 'm', 'n', 'p', 'q', 'r', 's', 't',
            'u', 'v', 'w', 'x', 'y', 'z' };

    public boolean isRotate() {
        return isRotate;
    }

    public void setRotate(boolean rotate) {
        isRotate = rotate;
    }

    /**
     * 验证码内容填充
     *
     * @param context 内容
     * @return Captcha
     */
    @Override
    public Captcha doFillContext(CaptchaContext context) {
        Captcha captcha = new Captcha();
        String content = context.getContent();
        Graphics2D graphics = context.getGraphics();
        int wordLength = content.length();
        int fW = context.getWidth() / wordLength;
        int fSp = (fW - (int) graphics.getFontMetrics()
                .getStringBounds(String.valueOf(wordLength), graphics).getWidth()) / 2;
        for (int i = 0; i < wordLength; i++) {
            String s = Character.toString(content.charAt(i));
            graphics.setColor(randomColor());
            int fY = context.getHeight()
                    - ((context.getHeight() - (int) graphics.getFontMetrics()
                    .getStringBounds(s, graphics).getHeight()) >> 1);
            int x = i * fW + fSp + 3;
            int y = fY - 3;
            double scale = 1.0;
            boolean isScale = false;
            // 开启旋转效果
            if (isRotate) {
                FontMetrics fontMetrics = graphics.getFontMetrics();
                int charWidth = fontMetrics.stringWidth(s);
                int charHeight = fontMetrics.getHeight();
                AffineTransform affineTransform = new AffineTransform();
                boolean isOdd = wordLength % 2 == 0;
                int middle = wordLength / 2;
                // 鱼眼效果：中间数字放大
                isScale = wordLength > 2 && ((!isOdd && i == middle) || (isOdd && (i == middle - 1 || i == middle)));
                scale = RandomUtils.random(1.1, 1.4);
                // 旋转角度&中心点
                affineTransform.rotate(Math.toRadians(RandomUtils.random(-60, 60)), x + (double) charWidth / 2 ,
                        y - (double) charHeight / 2);
                if (isScale) {
                    affineTransform.scale(scale, scale);
                }
                graphics.setTransform(affineTransform);
            }
            // 缩放之后，x,y坐标发生了变化
            if (isScale) {
                graphics.drawString(s, (int) (x / scale), (int) (y / scale));
                continue;
            }
            graphics.drawString(s, x, y);
        }
        graphics.setTransform(new AffineTransform());
        captcha.setAnswer(List.of(content));
        return captcha;
    }

    /**
     * 默认验证码内容
     *
     * @return String[]
     */
    @Override
    public String getContent() {
        return this.randomGenerate(len);
    }

    /**
     * 随机生成
     *
     * @param length 指定长度
     * @return String[]
     */
    public String randomGenerate(int length) {
        StringBuilder sb = new StringBuilder();
        Set<Integer> randomIndexs = new HashSet<>();
        for (int i = 0; i < length; i++) {
            int random;
            while (true) {
                random = random(ALPHA.length);
                if (!randomIndexs.contains(random)) {
                    randomIndexs.add(random);
                    break;
                }
            }
            sb.append(ALPHA[random]);
        }
        return sb.toString();
    }

    /**
     * 当前验证码类型
     *
     * @return String
     */
    @Override
    public String getType() {
        return CaptchaEnum.TEXT.getType();
    }

    /**
     * 字体
     *
     * @return Font 字体
     */
    @Override
    public Font getFont() {
        return fontProvider.get(FontEnum.SCANDAL.getName());
    }
}
